package com.library.service;

import com.library.dto.BookDTO;
import com.library.dto.PageResponse;
import com.library.entity.Book;
import com.library.exception.BusinessException;
import com.library.exception.NotFoundException;
import com.library.repository.BookRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 图书服务类
 * 负责处理图书相关的业务逻辑，包括搜索、查询、创建、更新、删除等操作
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BookService {
    // 图书数据访问层，用于数据库操作
    private final BookRepository bookRepository;

    /**
     * 搜索图书
     * 支持按关键词、分类、推荐状态进行搜索
     * 
     * @param keyword 搜索关键词，会在书名、作者、ISBN中搜索
     * @param category 图书分类，精确匹配
     * @param isRecommended 是否推荐，true表示只搜索推荐图书
     * @return 符合条件的图书列表
     */
    public List<BookDTO> searchBooks(String keyword, String category, Boolean isRecommended) {
        // 处理空字符串，将空字符串转换为null以便查询正确处理
        String keywordParam = (keyword != null && keyword.trim().isEmpty()) ? null : keyword;
        String categoryParam = (category != null && category.trim().isEmpty()) ? null : category;

        log.debug("搜索图书 - 关键词: {}, 分类: {}, 推荐: {}", keywordParam, categoryParam, isRecommended);
        // 调用Repository进行数据库查询
        Page<Book> page = bookRepository.searchBooks(
                keywordParam, categoryParam, isRecommended, PageRequest.of(0, 1000));
        List<Book> books = page.getContent();
        log.info("找到 {} 本图书", page.getTotalElements());
        // 将实体对象转换为DTO对象返回
        return books.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    /**
     * 搜索图书（分页和排序）
     * 支持按关键词、分类、推荐状态进行搜索，支持分页和排序
     * 
     * @param keyword 搜索关键词，会在书名、作者、ISBN中搜索
     * @param category 图书分类，精确匹配
     * @param isRecommended 是否推荐，true表示只搜索推荐图书
     * @param page 页码（从1开始）
     * @param size 每页大小
     * @param sort 排序字段
     * @param order 排序方向（asc/desc）
     * @return 分页的图书列表
     */
    public PageResponse<BookDTO> searchBooksWithPagination(
            String keyword, String category, Boolean isRecommended,
            Integer page, Integer size, String sort, String order) {

        // 参数处理：将空字符串转换为null，trim去除前后空格
        String keywordParam = StringUtils.hasText(keyword) ? keyword.trim() : null;
        String categoryParam = StringUtils.hasText(category) ? category.trim() : null;
        
        // 记录日志以便调试
        log.debug("搜索图书参数 - keyword: [{}], category: [{}], isRecommended: [{}], page: {}, size: {}", 
                keywordParam, categoryParam, isRecommended, page, size);

        // 构建排序规则
        Sort sortObj = Sort.by(Sort.Direction.fromString(order), sort);
        Pageable pageable = PageRequest.of(page - 1, size, sortObj);
        // 执行分页查询
        Page<Book> bookPage = bookRepository.searchBooks(
                keywordParam, categoryParam, isRecommended, pageable
        );
        
        log.info("搜索完成 - 找到 {} 本图书，关键词: [{}]", bookPage.getTotalElements(), keywordParam);
        // 转换DTO
        List<BookDTO> content = bookPage.getContent()
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        return new PageResponse<>(
                content,
                bookPage.getTotalElements(),
                bookPage.getNumber() + 1,
                bookPage.getSize(),
                bookPage.getTotalPages()
        );
    }
//    public PageResponse<BookDTO> searchBooksWithPagination(
//            String keyword, String category, Boolean isRecommended,
//            Integer page, Integer size, String sort, String order) {
//        // 处理空字符串
//        String keywordParam = (keyword != null && keyword.trim().isEmpty()) ? null : keyword;
//        String categoryParam = (category != null && category.trim().isEmpty()) ? null : category;
//
//        // 搜索图书（先获取所有结果，然后手动分页和排序）
//        List<Book> allBooks = bookRepository.searchBooks(keywordParam, categoryParam, isRecommended);
//
//        // 手动排序
//        String sortField = (sort != null && !sort.isEmpty()) ? sort : "createdAt";
//        boolean isDesc = "desc".equalsIgnoreCase(order);
//        allBooks.sort((a, b) -> {
//            int result = 0;
//            switch (sortField) {
//                case "title":
//                    result = (a.getTitle() != null ? a.getTitle() : "").compareTo(b.getTitle() != null ? b.getTitle() : "");
//                    break;
//                case "author":
//                    result = (a.getAuthor() != null ? a.getAuthor() : "").compareTo(b.getAuthor() != null ? b.getAuthor() : "");
//                    break;
//                case "stock":
//                    result = Integer.compare(a.getStock() != null ? a.getStock() : 0, b.getStock() != null ? b.getStock() : 0);
//                    break;
//                case "createdAt":
//                default:
//                    if (a.getCreatedAt() != null && b.getCreatedAt() != null) {
//                        result = a.getCreatedAt().compareTo(b.getCreatedAt());
//                    }
//                    break;
//            }
//            return isDesc ? -result : result;
//        });
//
//        // 手动分页
//        int start = (page - 1) * size;
//        int end = Math.min(start + size, allBooks.size());
//        List<Book> pagedBooks = start < allBooks.size() ?
//            allBooks.subList(Math.max(0, start), end) : List.of();
//
//        // 转换为DTO
//        List<BookDTO> content = pagedBooks.stream()
//                .map(this::convertToDTO)
//                .collect(Collectors.toList());
//
//        // 计算总页数
//        int totalPages = (int) Math.ceil((double) allBooks.size() / size);
//
//        return new PageResponse<>(content, (long) allBooks.size(), page, size, totalPages);
//    }

    /**
     * 根据ID获取图书详情
     * 
     * @param id 图书ID
     * @return 图书DTO对象
     * @throws BusinessException 当ID无效时抛出
     * @throws NotFoundException 当图书不存在时抛出
     */
    public BookDTO getBookById(Long id) {
        // 验证ID有效性
        if (id == null || id <= 0) {
            throw new BusinessException("图书ID无效");
        }
        
        // 从数据库查询图书
        Book book = bookRepository.findById(id)
                .orElseThrow(() -> {
                    log.warn("图书不存在: ID={}", id);
                    return new NotFoundException("图书不存在");
                });
        // 转换为DTO返回
        return convertToDTO(book);
    }

    /**
     * 创建新图书
     * 管理员专用功能
     * 
     * @param dto 图书信息DTO
     * @return 创建后的图书DTO（包含生成的ID）
     * @throws BusinessException 当数据验证失败或ISBN已存在时抛出
     */
    @Transactional  // 使用事务保证数据一致性
    public BookDTO createBook(BookDTO dto) {
        // 验证图书数据
        validateBookDTO(dto);
        
        // 检查ISBN是否已存在（ISBN必须唯一）
        if (dto.getIsbn() != null && !dto.getIsbn().trim().isEmpty()) {
            bookRepository.findByIsbn(dto.getIsbn()).ifPresent(book -> {
                throw new BusinessException("ISBN已存在: " + dto.getIsbn());
            });
        }
        
        // 将DTO转换为实体对象
        Book book = convertToEntity(dto);
        // 保存到数据库
        book = bookRepository.save(book);
        log.info("创建图书成功: {} (ID: {})", book.getTitle(), book.getId());
        // 转换回DTO返回
        return convertToDTO(book);
    }

    /**
     * 更新图书信息
     * 管理员专用功能
     * 
     * @param id 图书ID
     * @param dto 更新的图书信息
     * @return 更新后的图书DTO
     * @throws BusinessException 当ID无效或数据验证失败时抛出
     * @throws NotFoundException 当图书不存在时抛出
     */
    @Transactional
    public BookDTO updateBook(Long id, BookDTO dto) {
        // 验证ID有效性
        if (id == null || id <= 0) {
            throw new BusinessException("图书ID无效");
        }
        
        // 验证图书数据
        validateBookDTO(dto);
        
        // 查找要更新的图书
        Book book = bookRepository.findById(id)
                .orElseThrow(() -> {
                    log.warn("更新失败: 图书不存在 - ID={}", id);
                    return new NotFoundException("图书不存在");
                });
        
        // 检查ISBN是否与其他图书冲突（允许保持自己的ISBN不变）
        if (dto.getIsbn() != null && !dto.getIsbn().trim().isEmpty()) {
            bookRepository.findByIsbn(dto.getIsbn())
                    .filter(b -> !b.getId().equals(id))  // 排除当前图书
                    .ifPresent(b -> {
                        throw new BusinessException("ISBN已被其他图书使用: " + dto.getIsbn());
                    });
        }
        
        // 更新图书信息
        book.setTitle(dto.getTitle());
        book.setAuthor(dto.getAuthor());
        book.setIsbn(dto.getIsbn());
        book.setCategory(dto.getCategory());
        book.setDescription(dto.getDescription());
        // 只有非空值才更新库存和推荐状态
        if (dto.getStock() != null) {
            book.setStock(dto.getStock());
        }
        if (dto.getIsRecommended() != null) {
            book.setIsRecommended(dto.getIsRecommended());
        }
        
        // 保存更新
        book = bookRepository.save(book);
        log.info("更新图书成功: {} (ID: {})", book.getTitle(), book.getId());
        return convertToDTO(book);
    }

    /**
     * 删除图书
     * 管理员专用功能
     * 
     * @param id 图书ID
     * @throws BusinessException 当ID无效时抛出
     * @throws NotFoundException 当图书不存在时抛出
     */
    @Transactional
    public void deleteBook(Long id) {
        // 验证ID有效性
        if (id == null || id <= 0) {
            throw new BusinessException("图书ID无效");
        }
        
        // 检查图书是否存在
        if (!bookRepository.existsById(id)) {
            log.warn("删除失败: 图书不存在 - ID={}", id);
            throw new NotFoundException("图书不存在");
        }
        
        // 删除图书
        bookRepository.deleteById(id);
        log.info("删除图书成功: ID={}", id);
    }

    /**
     * 获取所有图书分类
     * 
     * @return 分类名称列表
     */
    public List<String> getAllCategories() {
        List<String> categories = bookRepository.findAllCategories();
        log.debug("获取所有分类: {} 个", categories.size());
        return categories;
    }

    /**
     * 获取图书统计信息
     * 
     * @return 图书统计信息
     */
    public Map<String, Object> getBookStatistics() {
        List<Book> allBooks = bookRepository.findAll();
        long totalBooks = allBooks.size();
        long totalStock = allBooks.stream().mapToLong(b -> b.getStock() != null ? b.getStock() : 0).sum();
        
        // 按分类统计
        Map<String, Long> categoryCount = allBooks.stream()
                .filter(b -> b.getCategory() != null && !b.getCategory().isEmpty())
                .collect(Collectors.groupingBy(Book::getCategory, Collectors.counting()));
        
        // 库存为0的图书数量
        long outOfStock = allBooks.stream().filter(b -> b.getStock() == null || b.getStock() == 0).count();
        
        // 推荐图书数量
        long recommendedBooks = allBooks.stream().filter(b -> b.getIsRecommended() != null && b.getIsRecommended()).count();
        
        Map<String, Object> statistics = new HashMap<>();
        statistics.put("totalBooks", totalBooks);
        statistics.put("totalStock", totalStock);
        statistics.put("categoryCount", categoryCount);
        statistics.put("outOfStock", outOfStock);
        statistics.put("recommendedBooks", recommendedBooks);
        
        log.info("获取图书统计信息: 总图书数={}, 总库存={}", totalBooks, totalStock);
        return statistics;
    }

    /**
     * 批量删除图书
     * 
     * @param bookIds 图书ID列表
     */
    @Transactional
    public void deleteBooksBatch(List<Long> bookIds) {
        if (bookIds == null || bookIds.isEmpty()) {
            throw new BusinessException("图书ID列表不能为空");
        }
        
        for (Long id : bookIds) {
            if (id != null && id > 0) {
                if (bookRepository.existsById(id)) {
                    bookRepository.deleteById(id);
                    log.info("批量删除图书: ID={}", id);
                }
            }
        }
    }

    /**
     * 批量更新图书
     * 
     * @param books 图书列表
     */
    @Transactional
    public void updateBooksBatch(List<BookDTO> books) {
        if (books == null || books.isEmpty()) {
            throw new BusinessException("图书列表不能为空");
        }
        
        for (BookDTO dto : books) {
            if (dto.getId() != null && dto.getId() > 0) {
                updateBook(dto.getId(), dto);
            }
        }
    }

    /**
     * 验证图书DTO数据的有效性
     * 
     * @param dto 图书DTO
     * @throws BusinessException 当数据不符合要求时抛出
     */
    private void validateBookDTO(BookDTO dto) {
        // 验证书名
        if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
            throw new BusinessException("书名不能为空");
        }
        if (dto.getTitle().length() > 200) {
            throw new BusinessException("书名长度不能超过200个字符");
        }
        // 验证作者
        if (dto.getAuthor() == null || dto.getAuthor().trim().isEmpty()) {
            throw new BusinessException("作者不能为空");
        }
        if (dto.getAuthor().length() > 100) {
            throw new BusinessException("作者名称长度不能超过100个字符");
        }
        // 验证ISBN长度
        if (dto.getIsbn() != null && dto.getIsbn().length() > 50) {
            throw new BusinessException("ISBN长度不能超过50个字符");
        }
        // 验证库存不能为负数
        if (dto.getStock() != null && dto.getStock() < 0) {
            throw new BusinessException("库存不能为负数");
        }
    }

    /**
     * 将Book实体转换为BookDTO
     * 
     * @param book 图书实体
     * @return 图书DTO
     */
    private BookDTO convertToDTO(Book book) {
        return new BookDTO(
                book.getId(), book.getTitle(), book.getAuthor(), book.getIsbn(),
                book.getCategory(), book.getDescription(), book.getStock(),
                book.getIsRecommended(), book.getCreatedAt());
    }

    /**
     * 将BookDTO转换为Book实体
     * 对字符串字段进行trim处理，设置默认值
     * 
     * @param dto 图书DTO
     * @return 图书实体
     */
    private Book convertToEntity(BookDTO dto) {
        Book book = new Book();
        book.setTitle(dto.getTitle().trim());
        book.setAuthor(dto.getAuthor().trim());
        book.setIsbn(dto.getIsbn() != null ? dto.getIsbn().trim() : null);
        book.setCategory(dto.getCategory() != null ? dto.getCategory().trim() : null);
        book.setDescription(dto.getDescription() != null ? dto.getDescription().trim() : null);
        book.setStock(dto.getStock() != null ? dto.getStock() : 0);
        book.setIsRecommended(dto.getIsRecommended() != null ? dto.getIsRecommended() : false);
        return book;
    }
}
